package org.zhaya.sdk.util;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.Objects;

public class JsonProcessorsUtils {

    private static final JsonMapper MAPPER = JsonMapper.builder()
            .defaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.NON_NULL))
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
            .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
            .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
            .enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
            .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
            .enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS)
            .addModules(new AfterburnerModule())
            .build();

    public static <T> T fromJsonString(Class<T> type, String json) {
        if (Objects.isNull(json) || json.isEmpty()) {
            throw new RuntimeException("json is either null or empty (json = " + json + ")");
        }

        try {
            return MAPPER.readValue(json, type);
        } catch (Exception e) {
            throw new RuntimeException("failed to deserialize object type=" + type + " from json=" + json, e);
        }
    }

    public static <T> T fromJsonMap(Class<T> type, Map<String, Object> json) {
        if (Objects.isNull(json)) {
            throw new RuntimeException("json map is null");
        }

        try {
            return MAPPER.convertValue(json, type);
        } catch (Exception e) {
            throw new RuntimeException("failed to deserialize object type=" + type + " from json=" + json, e);
        }
    }

    public static String toJsonString(Object jsonObject) {
        if (Objects.isNull(jsonObject)) {
            return null;
        }

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            MAPPER.writeValue(stream, jsonObject);
            return stream.toString();
        } catch (Exception e) {
            throw new RuntimeException("failed to serialize object =" +
                    StringUtils.abbreviate(jsonObject.toString(), 100)
                    + " to json. Error = " + e.getMessage(), e);
        }
    }

    public static boolean isList(String value) {
        boolean isList;
        try {
            JsonNode jsonNode = MAPPER.readTree(value);
            if (jsonNode.isEmpty()) {
                return false;
            }
            isList = jsonNode.isArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to read the json :" + value + StrUtil.COMMA + e.getMessage(), e);
        }
        return isList;
    }
}